﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Resources;
using System.IO;
using System.Reflection;

namespace TresselLS
{
    public partial class SimulatorForm : Form
    {
        /*#
        Variable Name: debugDisplay
        Module Where Defined: SimulatorForm
        Data Type: DebugForm
        Local or Global: Global
        Purpose: used to display the register values
        #*/
        private DebugForm debugDisplay;
        /*#
        Variable Name: stopRunning
        Module Where Defined: SimulatorForm
        Data Type: bool
        Local or Global: Global
        Purpose: tells the simulator that the form is closing
        #*/
        public bool stopRunning = false;
        /*#
        Variable Name: simulation
        Module Where Defined: SimulatorForm
        Data Type: TresselSimulator
        Local or Global: Global
        Purpose: runs the simulation
        #*/
        private TresselSimulator simulation;
        /*#
        Variable Name: inputString
        Module Where Defined: SimulatorForm
        Data Type: TresselSimulator
        Local or Global: Global
        Purpose: holds the value that the user typed for a READ-STR instruction
        #*/
        public string inputString = "";
        /*#
        Variable Name: linkerReference
        Module Where Defined: SimulatorForm
        Data Type: TresselLinker
        Local or Global: Global
        Purpose: holds the tressel linker for use by the class
        #*/
        private TresselLinker linkerReference;
        /*#
        Variable Name: inputNum
        Module Where Defined: SimulatorForm
        Data Type: TresselSimulator
        Local or Global: Global
        Purpose: holds the value that the user typed for a READ-NUM instruction
        #*/
        public int inputNum = 0;
        public SimulatorForm(TresselLinker linker)
        {
            /*!
            Procedure Name: SimulatorForm
            Description: constructor for the Simulator Form
            Input Parameters: TresselLinker linkerParam
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Who: Steve Rudy
            When: 11/24/2009
            Why: we needed to set a timer to make the form display before simulation
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            InitializeComponent();
            myTimer.Interval = 500;
            myTimer.Tick += new EventHandler(myTimerTick);
            linkerReference = linker;
            debugDisplay = new DebugForm();
            simulation = new TresselSimulator(linkerReference, this);
        }
        void myTimerTick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: myTimerTick
            Description: starts the simulation
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/24/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            myTimer.Stop();
            simulation.StartSimulator();
        }
        public void DisplayInstructions()
        {
            /*!
            Procedure Name: DisplayInstructions
            Description: populates the datagridview with the instructions
            Input Parameters: none
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            simulatorDataGridView.Rows.Clear();
            for (int i = 0; i < simulation.MemoryArray.Length; i++)
            {
                /*#
                Variable Name: rowToBeAdded
                Module Where Defined: DisplayInstructions
                Data Type: string[]
                Local or Global: Local
                Purpose: holds the values for the row to be added
                #*/
                string[] rowToBeAdded = { i.ToString(), simulation.MemoryArray[i].ToString() };
                simulatorDataGridView.Rows.Add(rowToBeAdded);
            }
        }
        public void UpdateRegisters()
        {
            /*!
            Procedure Name: UpdateRegisters
            Description: updates the DebugForm's content; called by the simulation
            Input Parameters: none
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            this.oldAC = newAC;
            this.oldBR = newBR;
            this.oldIR = newIR;
            this.oldSTAT = newSTAT;
            newAC = simulation.Accumulator;
            newIR = simulation.IndexRegister;
            newBR = simulation.BaseRegister;
            newSTAT = Converter.ToHex(simulation.theStatusRegister.ToBin());
            debugDisplay.UpdateRegisters(oldAC, oldIR, oldBR, oldSTAT, newAC, newIR, newBR, newSTAT);
        }
        public int GetNumFromUser()
        {
            /*!
            Procedure Name: GetNumFromUser
            Description: lets the user input a number for the simulator
            Input Parameters: none
            Output Parameters: int
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/22/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            /*#
            Variable Name: numInput
            Module Where Defined: GetNumFromUser
            Data Type: UserInputForm
            Local or Global: Local
            Purpose: acts as the interface for the user to enter a number
            #*/
            UserInputForm numInput = new UserInputForm(false, this);
            numInput.ShowDialog();
            return inputNum;
        }
        public string GetStringFromUser()
        {
            /*!
            Procedure Name: GetStringFromUser
            Description: lets the user input a string for the simulator
            Input Parameters: none
            Output Parameters: int
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/22/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/

            /*#
            Variable Name: strInput
            Module Where Defined: GetNumFromUser
            Data Type: UserInputForm
            Local or Global: Local
            Purpose: acts as the interface for the user to enter a string
            #*/
            UserInputForm strInput = new UserInputForm(true, this);
            strInput.ShowDialog();
            return inputString;
        }
        public void HighlightLine(int lineNum)
        {
            /*!
            Procedure Name: HighlightLine
            Description: highlights the next instruction, un-highlights the previous instruction, and centers the DataGridView onto the current instruction
            Input Parameters: none
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            if (lineNum < simulatorDataGridView.Rows.Count)
            {
                simulatorDataGridView.Rows[lastRowHighlighted].DefaultCellStyle.BackColor = SystemColors.Control;
                simulatorDataGridView.Rows[lineNum].DefaultCellStyle.BackColor = Color.Yellow;
                simulatorDataGridView.FirstDisplayedScrollingRowIndex = Math.Max(lineNum - halfWayConstant, 0);
                lastRowHighlighted = lineNum;
            }
        }
        public void DisplayMessage(string message)
        {
            /*!
            Procedure Name: DisplayMessage
            Description: displays the given message to the user
            Input Parameters: string message
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/22/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            MessageBox.Show(message);
        }
        public void DisableButtons()
        {
            /*!
            Procedure Name: DisableButtons
            Description: disables both the play and the step buttons
            Input Parameters: string message
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/29/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            this.stepButton.Enabled = false;
            this.playButton.Enabled = false;
        }
        public void DisplayAll(int lowestAddress, int highestAddress)
        {
            /*!
            Procedure Name: DisplayAll
            Description: called when the DISPLAY instruction is executed
            Input Parameters: none
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/22/2009
            Modification Log:
            Who: Steve Rudy
            When: 11/30/2009
            Why: only active memory locations should be displayed
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/

            /*#
            Variable Name: display
            Module Where Defined: CallDisplayForm
            Data Type: Timer
            Local or Global: Global
            Purpose: used to display the information required for the DISPLAY instruction
            #*/
            CallDisplayForm display = new CallDisplayForm(simulation.MemoryArray, lowestAddress, highestAddress,simulation.LocationCounter,this.oldAC,this.oldIR,this.oldBR,this.oldSTAT,this.newAC,this.newIR,this.newBR,this.newSTAT);
            display.ShowDialog();
        }
        private void PlayButtonClick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: PlayButtonClick
            Description: disables the play button, enables the step button, and sets playPush, stepPush, and step
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            simulation.playPush = true;
            simulation.stepPush = false;
            simulation.step = false;
            playButton.Enabled = false;
        }

        private void StepButtonClick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: StepButtonClick
            Description: disables the step button and enables the play button, and sets playPush, stepPush, and step
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            simulation.playPush = false;
            simulation.stepPush = true;
            simulation.step = true;
        }
        public void SetDebugDisplay(bool shouldDisplay)
        {
            /*!
            Procedure Name: SetDebugDisplay
            Description: shows the debug form
            Input Parameters: bool shouldDisplay
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/29/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            if (debugDisplay.Visible && !shouldDisplay)
            {
                debugDisplay.Visible = false;
            }
            else if (!debugDisplay.Visible && shouldDisplay)
            {
                debugDisplay.Location = new Point(this.Location.X + 362, this.Location.Y);
                debugDisplay.Visible = true;
                this.Focus();
            }
        }

        private void SimulatorFormMove(object sender, EventArgs e)
        {
            /*!
            Procedure Name: SimulatorFormMove
            Description: keeps the debug form next to the simulation form
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            if (debugDisplay.Visible)
            {
                debugDisplay.Location = new Point(this.Location.X + 362, this.Location.Y);
            }
        }
        private void SimulatorFormFormClosing(object sender, FormClosingEventArgs e)
        {
            /*!
            Procedure Name: SimulatorFormFormClosing
            Description: ensures that the debug form closes when the simulation form closes
            Input Parameters: object sender, FormClosingEventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Who: Steve Rudy
            When: 11/29/2009
            Why: needed to set stopRunning to true
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            stopRunning = true;
            //debugDisplay.Close();
        }

        private void SimulatorFormLoad(object sender, EventArgs e)
        {
            /*!
            Procedure Name: SimulatorFormLoad
            Description: sets the halfWayConstant, which is used to keep the DataGridView centered on the current instruction, and starts the display timer
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Who: Steve Rudy
            When: 11/29/2009
            Why: needed to set the halfWayConstant in another method, so it is now removed from this one
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            myTimer.Start();
        }
        public void SetHalfWayConstant()
        {
            /*!
            Procedure Name: SetHalfWayConstant
            Description: sets the halfWayConstant, which is used to keep the DataGridView centered on the current instruction
            Input Parameters: none
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/29/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            halfWayConstant = simulatorDataGridView.DisplayedRowCount(false) / 2;
        }
        /*#
        Variable Name: myTimer
        Module Where Defined: SimulatorForm
        Data Type: Timer
        Local or Global: Global
        Purpose: lets the form load completely before starting the simulation
        #*/
        private System.Windows.Forms.Timer myTimer = new Timer();
        private void simulatorDataGridViewSelectionChanged(object sender, EventArgs e)
        {
            /*!
            Procedure Name: simulatorDataGridViewSelectionChanged
            Description: Blocks the user from selecting instructions
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/21/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            /*#
            Variable Name: row
            Module Where Defined: simulatorDataGridViewSelectionChanged
            Data Type: DataGridViewRow
            Local or Global: Local
            Purpose: accesses each selected row in order to unselect it
            #*/
            foreach (DataGridViewRow row in simulatorDataGridView.SelectedRows)
            {
                row.Selected = false;
            }
        }

        private void simulatorDataGridViewCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            /*!
            Procedure Name: simulatorDataGridViewCellFormatting
            Description: formats the location of each instruction into padded hex
            Input Parameters: object sender, DataGridViewCellFormattingEventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/29/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            if (e.ColumnIndex == 0 && e.Value.ToString().Length > 0)
            {
                e.Value = Converter.ToHex(System.Convert.ToInt32(e.Value)).Remove(0,3);
            }
            else if (e.ColumnIndex == 1 && e.Value.ToString().Length > 0)
            {
                e.Value = ((string)e.Value).PadLeft(6, '0');
            }
        }

        private void SimulatorFormFormClosed(object sender, FormClosedEventArgs e)
        {
            /*!
            Procedure Name: SimulatorFormFormClosed
            Description: closes the debug form when the main form closes
            Input Parameters: object sender, FormClosedEventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/29/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            debugDisplay.Close();
        }

        private void updateMemoryButtonClick(object sender, EventArgs e)
        {
            /*!
            Procedure Name: updateMemoryButtonClick
            Description: updates the displayed memory contents
            Input Parameters: object sender, EventArgs e
            Output Parameters: none
            Error Conditions Tested:
            Error Messages Generated:
            Original Author: Steve Rudy
            Procedure Creation Date: 10/29/2009
            Modification Log:
            Coding Standards Met: SR
            Testing Standards Met: RM
            !*/
            simulatorDataGridView.Rows.Clear();
            for (int i = 0; i < simulation.MemoryArray.Length; i++)
            {
                this.simulatorDataGridView.Rows.Add(i.ToString(), simulation.MemoryArray[i].ToString());
            }
            HighlightLine(simulation.LocationCounter);
        }
    }
}
